Skip to content

docs(docker): add an example of building distroless image#1900

Merged
henderkes merged 7 commits intophp:mainfrom
damienfern:docs/distroless-build
Jan 26, 2026
Merged

docs(docker): add an example of building distroless image#1900
henderkes merged 7 commits intophp:mainfrom
damienfern:docs/distroless-build

Conversation

@damienfern
Copy link
Contributor

Related to #151, this PR adds an example about how building a distroless image for a Frankenphp project.

FYI, on https://github.com/dunglas/symfony-docker, it only saves ~24MB in the image size.

I think we could go even further by building our own distroless image with Bazel like they do here but for now, the doc is a good start.

@henderkes
Copy link
Contributor

henderkes commented Sep 27, 2025

I don't understand the point of this. If you want the smallest possible file size, you want to go for a static musl binary with a bare linux kernel system. Statically linking everything ends up much smaller than linking against shared libraries, because dead code is stripped out, rather than preserved for dynamic exports.

And at that point, you don't need Docker anymore.

What you documented here will most definitely blow up when you attempt to use anything that loads a shared library. The docker container links against all libraries dynamically. And by using bookworm as the base, it itself wouldn't even run on a real "distroless" image, only on the stripped debian ones, because it links dynamically against glibc.

@damienfern
Copy link
Contributor Author

Thanks for your feedback 🙏.

I don't understand the point of this. If you want the smallest possible file size, you want to go for a static musl binary with a bare linux kernel system. Statically linking everything ends up much smaller than linking against shared libraries, because dead code is stripped out, rather than preserved for dynamic exports.

The main benefit of distroless images are security and image size : getting only things needed guarantees a minimal attack surface as it contains only your app and runtime deps (no package manager/shell/debugging tools/not even an echo).
The main purpose of this documentation is to help FrankenPHP users building secure and small images. Based on Frankenphp documentation, using musl leads to performance degradation compared to glibc and to weird bugs, so I didn’t even try.
Using static-builder-gnu was my first guess, but AFAIK static-builder-gnu provides the last PHP version and doesn’t let you choose (I might be wrong on this).

And at that point, you don't need Docker anymore.
What you documented here will most definitely blow up when you attempt to use anything that loads a shared library. The docker container links against all libraries dynamically. And by using bookworm as the base, it itself wouldn't even run on a real "distroless" image, only on the stripped debian ones, because it links dynamically against glibc.

You’re right, that’s why I’m using the same Debian version between builder and distroless stage and copying the entire shared library.

Do you have anything in mind that could help ?

@henderkes
Copy link
Contributor

henderkes commented Oct 1, 2025

Based on Frankenphp documentation, using musl leads to performance degradation compared to glibc

Very minimal when using mimalloc. Even with the default allocator, you're only going to notice differences in heavily threaded scenarios. Using higher optimisation options will yield you 10%+++ better performance over debians/ubuntus php distributions, not to mention PGO.

The gnu static builder supports the same options as the musl one.

Do you have anything in mind that could help ?

Not particularly, but this approach seems like it will inevitably break things at some point. If someone is so starven of storage space that 6mb less (vs alpine) make a difference, perhaps they shouldn't be using frankenphp with a 50mb footprint, plus php with a ~35mb footprint.

@henderkes
Copy link
Contributor

Given that Debian 12 is actually bookworm and all shared libraries are copied over, this would actually work. I need to retract my statement about this likely leading to crashes. Since distroless and hardened images are all the hype now, it might be useful to tidy this up a bit and get it merged. @damienfern are you willing to add dhi as an alternative, update to trixie (debian 13), php 8.5.x and remove the old /lib/ folder, or should I adjust it as needed?

@AlliBalliBaba
Copy link
Contributor

Do you mind if I clean up this PR a bit @damienfern ?

Copy link
Contributor

@henderkes henderkes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't ran the proposed build, but it looks good now.

@AlliBalliBaba
Copy link
Contributor

It's been working for me with a Laravel application and these extensions gd pdo_mysql pdo_pgsql opcache apcu redis zip ftp simplexml intl. The resulting image is roughly 4x smaller. I've only tried distroless, not the docker hardened image. I was under the impression that they are open source now, but it seems like you still need an account to pull them.

@damienfern
Copy link
Contributor Author

Sorry for the silence. I've been running this since I created this PR and it works great. @AlliBalliBaba thank you for taking care of this, I will test your proposed build soon.

@damienfern
Copy link
Contributor Author

Tested with a Symfony project from https://github.com/dunglas/symfony-docker and it works great ! As @AlliBalliBaba, the image is 4x smaller than default image.

✅ (I cannot approve my own PR)

@henderkes henderkes merged commit 227977e into php:main Jan 26, 2026
1 check passed
@henderkes
Copy link
Contributor

Thank you both!

@dunglas
Copy link
Member

dunglas commented Jan 27, 2026

Awesome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants